package transaction

import (
	"TDD/src/user"
	"errors"
    "fmt"
	"math/big"
	"sync"
)

type Transaction struct {
    ID      int
    From    *user.User
    To      *user.User
    Amount  float64
}

type TransactionResult struct {
    TransactionID   int
    Success         bool
    Message         string
}

func (t *Transaction) CheckAmount() bool {
    return t.Amount > 0
}

func (t *Transaction) CheckBalance() bool {
    var prec uint = 16

    fromBalanceBig := big.NewFloat(t.From.Balance).SetPrec(prec)
    amountBig := big.NewFloat(t.Amount).SetPrec(prec)

    return t.From.Balance > 0 && fromBalanceBig.Cmp(amountBig) >= 0
}

func (t *Transaction) ConfirmTransaction() (float64, error) {
    if t.CheckAmount() && t.CheckBalance() {
        t.From.Balance -= t.Amount
        t.To.Balance += t.Amount
        return t.From.Balance, nil
    }

    return t.From.Balance, errors.New("Invalid amount or from-user balance")
}

func ProcessTransactions(transactions <- chan Transaction, results chan <- TransactionResult,
                         wg *sync.WaitGroup) {
    defer wg.Done()
    for t := range transactions {
        _, err := t.ConfirmTransaction()
        if err != nil {
            results <- TransactionResult{TransactionID: t.ID,
                                         Success: false,
                                         Message: "fail"}
            t.From.NotifyUser(t.ID, "транзакция не прошла")
        } else {
            results <- TransactionResult{TransactionID: t.ID, 
                                         Success: true, 
                                         Message: "ok"}
            t.ConfirmTransaction()
            t.From.NotifyUser(t.ID, "транзакция успешна")
            t.To.NotifyUser(t.ID, fmt.Sprintf("поступило %.2f ден. ед.", t.Amount))
        }
    }

    <- transactions
}
